package com.tangxz.generate_code.util;

import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;


@Slf4j
public class TemplateUtil {
    /**
     * 1、返回模板的实例，Configuration
     * 2、得到配置目录下的全部模板并返回（需要忽略模板）
     * 3、得到模板真实文件全路径
     * 4、通过模板创建文件
     */
    //模板中需要忽略的文件
    static List<String> ignoreFile;
    //模板中需要忽略后缀文件
    static List<String> ignoreSuffix;

    static {
        ignoreFile = new ArrayList<>();
        ignoreSuffix = new ArrayList<>();
        ignoreFile.add(".svn");
        ignoreFile.add("CVS");
        ignoreFile.add(".cvsignore");
        ignoreFile.add(".copyarea.db");
        ignoreFile.add("SCCS");
        ignoreFile.add("vssver.scc");
        ignoreFile.add(".DS_Store");
        ignoreFile.add(".git");
        ignoreFile.add(".gitignore");
        ignoreSuffix.add(".ftl");
    }

    /**
     * 得到模板配置器
     *
     * @return 根据模板根目录绝对地址，返回模板配置器
     * @throws IOException
     */
    public static Configuration getConfiguration(File templateRootDir) {
        Configuration c = new Configuration(Configuration.getVersion());
        //初始化模板实例的根目录
        log.info("--- Configuration 初始化模板文件路径：" + templateRootDir);
        try {
            c.setDirectoryForTemplateLoading(templateRootDir);
            c.setDefaultEncoding(FieldUtil.encoding);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return c;
    }

    public static void main(String[] args) {
        log.info("123");
    }

    /**
     * 得到当前需要生成的模板文件
     *
     * @param templateRootDir
     * @return 符合条件的需要生成的文件集合
     */
    public static List<File> getTemplateFiles(File templateRootDir) {
        List<File> templateFiles = new ArrayList<File>();
        //扫描模板文件，放入templateFiles集合中
        log.info("--- 开始 扫描模板文件");
        loadTemplateFiles(templateRootDir, templateFiles);
        //根据文件目录级别排序，必须先创建的需要先创建
        templateFiles.sort(Comparator.comparing(File::getAbsolutePath));
        log.info("--- 结束 扫描模板文件");
        return templateFiles;
    }

    /**
     * 递归得到所有需要生成的文件
     *
     * @param file          当前文件/目录
     * @param templateFiles 当前文件集合
     */
    public static void loadTemplateFiles(File file, List<File> templateFiles) {
        //如果当前遍历为隐藏、目录、且名字后缀不包含忽略后缀，则进入判断是否是空目录。，如不是空目录则递归
        if (!file.isHidden() && file.isDirectory() && !isIgnoreSuffix(file)) {
            File[] var = file.listFiles();
            for (int i = 0; i < (var != null ? var.length : 0); ++i) {
                //是目录则继续遍历
                loadTemplateFiles(var[i], templateFiles);
            }
            //如果不是目录且不忽略，则直接存入集合
        } else if (!isIgnoreSuffix(file) && !isIgnoreFile(file)) {
            //如果是文件，并且后缀和文件名都不忽略，才存入
            templateFiles.add(file);
            log.info("--- 找到模板文件：" + file.getName());
        }
    }

    /**
     * 是否是需要忽略的文件
     *
     * @param file
     * @return
     */
    private static boolean isIgnoreFile(File file) {
        for (String s : ignoreFile) {
            if (file.getName().equals(s)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 是否是需要忽略的后缀文件
     *
     * @param file
     * @return
     */
    private static boolean isIgnoreSuffix(File file) {
        for (String s : ignoreSuffix) {
            if (file.getName().endsWith(s)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 得到模板文件相较于模板根目录的路径
     *
     * @param templateRootDir 当前模板的根目录
     * @param templateFile    当前模板文件的全路径
     * @return
     */
    public static String getRelativePath(File templateRootDir, File templateFile) {
        if (templateRootDir.equals(templateFile)) {
            return "";
        } else {
            return templateRootDir.getParentFile() == null ? templateFile.getAbsolutePath().substring(templateRootDir.getAbsolutePath().length()) : templateFile.getAbsolutePath().substring(templateRootDir.getAbsolutePath().length() + 1);
        }
    }

    /**
     * @param filePath E:\eclipse2018-workspace\jeecg-boot\src/main/java\org\jeecg\modules\demo\demo\controller\DemoController.java
     * @return 生成文件路径，并返回文件
     * 初始化文件路径，返回文件名
     */
    public static File initFilePath(String filePath) {
        if (filePath == null) {
            throw new IllegalArgumentException("file must be not null");
        } else {
            File file = new File(filePath);
            initPath(file);
            return file;
        }
    }

    /**
     * 初始化文件路径
     *
     * @param file
     */
    public static void initPath(File file) {
        if (file.getParentFile() != null) {
            file.getParentFile().mkdirs();
        }
    }

    /**
     * 返回当前生成文件的类路径
     *
     * @param templatePath 当前需要生成文件类位置 java\${bussiPackage}\${entityPackage}\entity\${entityName}.javai
     * @param tableInfo
     * @param configuration
     * @return
     */
    public static String getTemplatePath(String templatePath, Map<String, Object> tableInfo, Configuration configuration) {
        StringWriter sw = new StringWriter();
        try {
            Template template = new Template("templateString...", new StringReader(templatePath), configuration);
            template.process(tableInfo, sw);
            templatePath = sw.toString();
            int start = 0, end = templatePath.length();
            if (templatePath.endsWith("i")) {
                end = templatePath.length() - 1;
            }
            if (templatePath.startsWith("java")) {
                start = 4;
            }
            String suffix = templatePath.substring(templatePath.lastIndexOf("."), end);
            templatePath = templatePath.substring(start, templatePath.lastIndexOf(".")).replace(".", File.separator);
            return templatePath + suffix;
        } catch (Exception e) {
            throw new IllegalStateException("cannot process templateString:" + templatePath + " cause:" + e, e);
        }
    }
}
